local Color = _ENV.import("./Color.lua");
local Style = commonlib.inherit(nil);

local function ToColor(value)
	return Color.ToColor(value);
end

local dimension_fields = {
	["height"] = true, ["min-height"] = true, ["max-height"] = true,
	["width"] = true, ["min-width"] = true, ["max-width"] = true,
	["left"] = true, ["top"] = true, ["right"] = true, ["bottom"] = true,
	["padding"] = true, ["padding-top"] = true, ["padding-right"] = true, ["padding-bottom"] = true, ["padding-left"] = true,
	["margin"] = true, ["margin-top"] = true, ["margin-right"] = true, ["margin-bottom"] = true, ["margin-left"] = true,
	["border-width"] = true, ["border-top-wdith"] = true, ["border-right-wdith"] = true, ["border-bottom-wdith"] = true, ["border-left-wdith"] = true,
	["spacing"] = true,
	["shadow-quality"] = true,
	["text-shadow-offset-x"] = true,
	["text-shadow-offset-y"] = true,
}

local number_fields = {
	["border-top-width"] = true, ["border-right-width"] = true, ["border-bottom-width"] = true, ["border-left-width"] = true, ["border-width"] = true,
	["outline-width"] = true,

	["font-size"] = true, ["base-font-size"] = true,
	["z-index"] = true,
	["scale"] = true,
	["flex-grow"] = true,
	["flex-shrink"] = true,

	["border-radius"] = true,

	["animation-iteration-count"] = true,
	["rotate"] = true,
	["translateX"] = true,
	["translateY"] = true,
};

local color_fields = {
	["color"] = true,
	["border-color"] = true,
	["border-top-color"] = true, ["border-right-color"] = true, ["border-bottom-color"] = true, ["border-left-color"] = true,
	["outline-color"] = true,
	["background-color"] = true,
	["outer-background-color"] = true,
	["shadow-color"] = true,
	["caret-color"] = true,
};

local image_fields = {
	["background"] = true,
	["background-image"] = true,
}

local time_fields = {
	["animation-duration"] = true,
	["animation-delay"] = true,
}

local transform_fields = {
	["transform"] = true,
	["transform-origin"] = true,
};

-- 缩写字段
local complex_fields = {
	["border"] = "border-width border-style border-color",
	["border-top"] = "border-top-width border-top-style border-top-color",
	["border-right"] = "border-right-width border-right-style border-right-color",
	["border-bottom"] = "border-bottom-width border-bottom-style border-bottom-color",
	["border-left"] = "border-left-width border-left-style border-left-color",
	["border-width"] = "border-top-width border-right-width border-bottom-width border-left-width",
    ["padding"] = "padding-top padding-right padding-bottom padding-left",
	["margin"] = "margin-top margin-right margin-bottom margin-left ",
	["overflow"] = "overflow-x overflow-y",
	["flex"] = "flex-grow flex-shrink flex-basis",
	["animation"] = "animation-name animation-duration animation-timing-function animation-delay animation-iteration-count animation-direction animation-fill-mode animation-play-state",
};

local inheritable_fields = {
	["color"] = true,
	["font-family"] = true,
	["font-size"] = true,
	["font-weight"] = true,
	["text-shadow"] = true,
	["shadow-color"] = true,
	["text-shadow-offset-x"] = true,
	["text-shadow-offset-y"] = true,
	["text-align"] = true,
	["line-height"] = true,
	["caret-color"] = true,
	["text-singleline"] = true,
	["base-font-size"] = true,
	["white-space"] = true,
};

-- local function IsPx(value)
-- 	return string.match(value or "", "^[%+%-]?%d+px$");
-- end

-- local function GetPxValue(value)
-- 	if (type(value) ~= "string") then return value end
-- 	return tonumber(string.match(value, "[%+%-]?%d+"));
-- end

-- local function IsNumber(value)
-- 	return string.match(value or "", "[%+%-]?%d+%.?%d*$");
-- end

-- local function GetNumberValue(value)
-- 	return tonumber(value);
-- end

local function GetTransformStyleValue(value)
	local transform = {};
	value = string.gsub(value, "^%s*", "");
	while(string.len(value) > 0) do
		if (string.find(value, "rotate", 1, true) == 1) then
			local str = string.match(value, "^(rotate%([^%)]*%))");
			value = string.sub(value, string.len(str) + 1);
			value = string.gsub(value, "^%s*", "");
			local degree =  string.match(str, "([%+%-]?%d+)");
			table.insert(transform, {action = "rotate", rotate = tonumber(degree)});
		end

		if (string.find(value, "translate", 1, true) == 1) then
			local str = string.match(value, "^(translate%([^%)]*%))");
			value = string.sub(value, string.len(str) + 1);
			value = string.gsub(value, "^%s*", "");
			local splitIndex = string.find(str, ",", 1, true);
			local x =  string.match(string.sub(str, 1, splitIndex), "([%+%-]?%d+)");
			local y =  string.match(string.sub(str, splitIndex or 1), "([%+%-]?%d+)");
			table.insert(transform, {action = "translate", translateX = tonumber(x), translateY = tonumber(y)});
		end

		if (string.find(value, "scale", 1, true) == 1) then
			local str = string.match(value, "^(scale%([^%)]*%))");
			value = string.sub(value, string.len(str) + 1);
			value = string.gsub(value, "^%s*", "");
			local splitIndex = string.find(str, ",", 1, true) or 1;
			local x =  string.match(string.sub(str, 1, splitIndex), "([%+%-]?%d+)");
			local y =  string.match(string.sub(str, splitIndex or 1), "([%+%-]?%d+)");
			table.insert(transform, {action = "scale", scaleX = tonumber(x), scaleY = tonumber(y)});
		end
	end
	-- echo(transform, true)
	return transform;
end

local function GetStyleValue(name, value)
	if (type(name) ~= "string" or type(value) ~= "string") then return value end
	-- auto 返回空取默认值
	if (value == "auto") then return nil end

    if(dimension_fields[name]) then
		if (string.match(value, "^[%+%-]?%d+px$")) then      -- 像素值
			value = tonumber(string.match(value, "^([%+%-]?%d+)px$"));
		elseif (string.match(value, "^[%+%-]?%d+%%$")) then  -- 百分比
			value = value;
		else
			value = nil;
		end
	elseif (number_fields[name]) then
		value = tonumber(string.match(value, "[%+%-]?%d+"));
	elseif(color_fields[name]) then
		value = ToColor(value);
	elseif(transform_fields[name]) then
		if(name == "transform") then
			value = GetTransformStyleValue(value);
		elseif(name == "transform-origin") then
			local values = {}
			for v in value:gmatch("%-?%d+") do
				values[#values+1] = tonumber(v);
			end
			if(values[1]) then
				values[2] = values[2] or 0;
				value = values;
			else
				value = nil;
			end
		end
	elseif(image_fields[name]) then
		value = string.gsub(value, "url%((.*)%)", "%1");
		value = string.gsub(value, "#", ";");
		value = value ~= "" and value or nil;
	elseif (time_fields[name]) then
		value = string.match(value, "%d+");
		value = value and tonumber(value);
	end
	return value;
end

local function AddSingleStyleItem(style, name, value)
	value = GetStyleValue(name, value);
	if (not value) then return end
	style[name] = value;
end

local function AddComplexStyleItem(style, name, value)
	local names = commonlib.split(complex_fields[name], "%s");
    local values = commonlib.split(tostring(value), "%s");

	-- 保留简写值
	AddSingleStyleItem(style, name, value);

	-- 解析符合样式值
	if (name == "padding" or name == "margin" or name == "border-width") then
		values[1] = values[1] or 0;
		values[4] = values[4] or values[2] or values[1];
        values[3] = values[3] or values[1];
		values[2] = values[2] or values[1];
	elseif (name == "border" or name == "border-top" or name == "border-right" or name == "border-bottom" or name == "border-left") then
		values[1] = values[1] or 0;
		values[2] = values[2] or "solid";
		values[3] = values[3] or "#000000";
		values[1] = values[1] == "none" and 0 or values[1];
	elseif (name == "overflow") then
		values[1] = values[1] or "hidden";
		values[2] = values[2] or values[1];
	elseif (name == "flex") then
		values[1] = values[1] or 1;
		values[2] = values[2] or 1;
		values[3] = values[3] or "auto";
	elseif (name == "animation") then
		values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8] = values[1], values[2] or "0s", values[3] or "linear", values[4] or "0s", values[5] or 1, values[6] or "normal", values[7], values[8];
    end

	for i = 1, #names do
		if (complex_fields[names[i]]) then
			AddComplexStyleItem(style, names[i], values[i]);
		else
			AddSingleStyleItem(style, names[i], values[i]);
		end
	end
end

local function AddStyleItem(style, name, value)
	name = string.lower(name);
	if (type(value) == "string") then value = string.gsub(value, "%s*$", "") end

	if(complex_fields[name]) then
		AddComplexStyleItem(style, name, value);
	else
		AddSingleStyleItem(style, name, value);
	end
end

local function ParseString(style_code)
	local style = {};
	for name, value in string.gmatch(style_code or "", "([%w%-]+)%s*:%s*([^;]*)[;]?") do
		AddStyleItem(style, name, value);
	end
	return style;
end

local function ParseTable(style_table)
	local style = {};
	for key, val in pairs(style_table) do
		AddStyleItem(style, key, val);
	end
	return style;
end

local function ParseStyle(text)
    if (type(text) == "string") then return ParseString(text) end
    if (type(text) == "table") then return ParseTable(text) end
	return {};
end

function Style:ctor()
	self.m_styles = {};
end

function Style:Clear()
	self.m_styles = {};
end

function Style:Init(text)
    self.m_styles = ParseStyle(text);
	return self;
end

-- 追加样式文本
function Style:AppendStyleText(text)
	local styles = ParseStyle(text)
	commonlib.partialcopy(self.m_styles, styles);
	return self;
end

-- 追加样式
function Style:AppendStyle(style)
	if (not style) then return end
	commonlib.partialcopy(self.m_styles, style.m_styles);
end

-- 设置样式文本
function Style:SetStyleText(text)
	self.m_styles = ParseStyle(text);
end

-- 设置样式项值
function Style:SetStyleValue(style_key, style_value)
	AddStyleItem(self.m_styles, style_key, style_value);
end

-- 获取样式项值
function Style:GetStyleValue(style_key, default_value)
	return self.m_styles[style_key] or default_value;
end

-- 获取像素样式值
function Style:GetPixelStyleValue(style_key, default_value, base_value)
	local value = self.m_styles[style_key] or default_value;
	if (type(value) ~= "string") then return value end
	local percentage = string.match(value, "^(%d+)%%$");
	if (not percentage) then return default_value end
	return math.floor(percentage * base_value / 100);
end

-- 获取样式数据
function Style:GetStyleData()
	return self.m_styles;
end

-- 是否是继承样式项
function Style.IsCanInherit(style_key)
	return inheritable_fields[style_key];
end

return Style;